//ScheduleIndividual.cpp
//Kathryn Glowinski
//Implementation of the ScheduleIndividual class

#include <string>
#include <vector>
#include <vector>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include "scheduleindividual.h"

ScheduleIndividual :: ScheduleIndividual(int vecSize, ScheduleConflicts* sCons, int timeSlots){

        mySize = vecSize;
        myVec = new vector<int>();
        myFit = 0.0;
        sc = sCons;
        times = timeSlots;
}

//Populate from the list compiled from thesplit string
void ScheduleIndividual :: populateFromList(QStringList list){

    for (int i = 0; i < mySize; i++){
        int num = list.at(i).toInt();

        myVec->push_back(num);
    }
    myFit = calculateFitness();
}

//Want to assign a random number between 0 and k, which will serve as
//the time slot assigned to that class
void ScheduleIndividual :: populateRandomly(){

        for (int i = 0; i < mySize; i++){

                int random = rand() % times;
                myVec->push_back(random);
        }
        myFit = calculateFitness();

}

double ScheduleIndividual :: calculateFitness(){

        int conflicts = 0;
        double possibleConflicts = 0;

        for (int i = 1; i < sc->numClasses; i ++){
                for (int j = i + 1; j < sc->numClasses; j++){
                        //if i and j are at the same time, and the table says there's a conflict
                        if ((myVec->at(i) == myVec->at(j)) &&
                                        (sc->conflicts[i][j] == 1)){
                                conflicts++;
                        }
                        possibleConflicts++;
                }
        }
        double fitness = 1 - (conflicts/possibleConflicts);
        return fitness;
}

double ScheduleIndividual :: getFitness(){
        return myFit;
}

string ScheduleIndividual :: print() {
        std::string self;
        std::stringstream out;
        for (int i = 0; i < mySize; i++){
                out << myVec->at(i);
                //putting a space in the string of times, can have indexes here if we want
                out << " ";
        }
        self = out.str();
        return self;
}

void ScheduleIndividual :: reproduce(ScheduleIndividual* par1, ScheduleIndividual* par2, int xover){
        //get the bits from the vector within the local BitIndiv.
                for (int i = 0; i < xover; i++){
                        myVec->push_back(par1->myVec->at(i));
                }

                for (int j = xover; j< mySize; j ++){
                        myVec->push_back(par2->myVec->at(j));
                }

                //Mutation: with a 1/mySize chance, will mutate elements such that
                //an element has a small chance of being replaced by a random int 0-(k-1)
                for (int m = 0; m < mySize; m++){

                        double chance = fRand(0, 1);

                        if (chance < (1.0 / mySize)){
                                //myVec[m] = rand() % times;
                                myVec->erase(myVec->begin() + m);
                                myVec->insert(myVec->begin()+m, 1, rand() % times);
                        }
                }

                //Get the fitness of the new vector
                myFit = calculateFitness();
}

double ScheduleIndividual :: fRand(double fMin, double fMax){
    double f = (double)rand() / RAND_MAX;
    return fMin + f * (fMax - fMin);
}

ScheduleIndividual* ScheduleIndividual :: clone() {
        ScheduleIndividual* sClone = new ScheduleIndividual(mySize, sc, times);
        sClone->myFit = myFit;

        for (int i = 0; i < mySize; i++){
                sClone->myVec->push_back(myVec->at(i));
        }
        return sClone;
}

ScheduleIndividual :: ~ScheduleIndividual() {
        delete myVec;
}
